package game.map.generator;

import game.graphics.Block;
import helpers.Interpolator;

import java.io.Serializable;
import java.util.Random;

import data.DataManager;

/**
 * Class for generating maps.
 * 
 * @author Drahomir Karchnak, Tomas Zima
 */
public class Generator implements Serializable
{
	/**
	 * Constructor.
	 * 
	 * @param blocks
	 */
	public Generator(Block blocks[][])
	{
		// Save pointer to all blocks 
		this.blocks = blocks;
		
		// Calculate size of map
		this.mapWidth	= blocks.length;
		this.mapHeight	= blocks[0].length;
		
		// Create instance of all other generator
		this.treeGenerator = new TreeGenerator(blocks);
	}
	
	
	/**
	 * Generate whole map.
	 */
	public void generate()
	{
		// pregenerate empty blocks
		for (int i = 0; i < mapWidth; i++)
		{
			for (int j = 0; j < mapHeight; j++)
			{
				blocks[i][j] = new Block(DataManager.BlockType.BLOCK_NONE, DataManager.BlockType.BACKGROUND_HEAVEN);
			}
		}
		
		// pregenerate heights
		int heights[] = new int[mapWidth / betweenDistances];
		
		for (int i = 0; i < heights.length; i++)
		{
			int max;

			// based on priority
			/*switch (randomizer.nextInt(40))
			{
				case 0:
					max = 80; 
					break;
					
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
					max = 60;
					break;
					
				case 6:
				case 7:
				case 8:
				case 9:
				case 10:
				case 11:
				case 12:
				case 13:
				case 14:
				case 15:
					max = 40;
					
				default:
					max = 20;
					break;
			}*/
			
			int n = randomizer.nextInt(40);
			
			if (n == 0)
			{
				max = 80;
			}
			else
			if (n >= 1 && n <= 5)
			{
				max = 60;
			}
			else
			if (n >= 6 && n <= 15)
			{
				max = 40;
			}
			else
			{
				max = 20;
			}
			
			heights[i] = randomizer.nextInt(max) + mapHeight / 2;
		}
		
		// generate map
		for (int i = betweenDistances; i < mapWidth; i++)
		{
			int prev	= heights[i / betweenDistances - 1];
			int next	= heights[i / betweenDistances];

			double x	= ((double) i % betweenDistances) / betweenDistances;
			int t		= (int) Interpolator.CosineInterpolate(x, prev, next);
				
			blocks[i][t] = new Block(DataManager.BlockType.BLOCK_GRASS, DataManager.BlockType.BACKGROUND_GRASS);

			t++;
			int u = 0;
			
			while (t < mapHeight)
			{
				if (u > 10)
				{
					if (u < 20 && u > 50)
					{
						if (randomizer.nextInt(2) == 0)
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_STONE, DataManager.BlockType.BACKGROUND_STONE);
						}
						else
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_DIRT, DataManager.BlockType.BACKGROUND_DIRT);
						}
					}
					else
					if (u > 50 && u < 80)
					{
						if (randomizer.nextInt(20) == 0)
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_COAL, DataManager.BlockType.BACKGROUND_STONE);
						}
						else
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_STONE, DataManager.BlockType.BACKGROUND_STONE);
						}
					}
					else
					if (u > 80 && u < 100)
					{
						if (randomizer.nextInt(10) == 0)
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_COAL, DataManager.BlockType.BACKGROUND_STONE);
						}
						else
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_STONE, DataManager.BlockType.BACKGROUND_STONE);
						}
					}
					else
					if (u > 100)
					{
						if (randomizer.nextInt(5) == 0)
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_COAL, DataManager.BlockType.BACKGROUND_STONE);
						}
						else
						{
							blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_STONE, DataManager.BlockType.BACKGROUND_STONE);
						}
					}
					else
					{
						blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_STONE, DataManager.BlockType.BACKGROUND_STONE);
					}
				}
				else
				{
					blocks[i][t++] = new Block(DataManager.BlockType.BLOCK_DIRT, DataManager.BlockType.BACKGROUND_DIRT);
				}
				
				u++;
			}
		}
		
		for (int i = 0; i < 4096; i++) blocks[i][0].setBlockType(DataManager.BlockType.BLOCK_BEDROCK);
		for (int i = 0; i < 4096; i++) blocks[i][1023].setBlockType(DataManager.BlockType.BLOCK_BEDROCK);
		for (int j = 0; j < 1024; j++) blocks[0][j].setBlockType(DataManager.BlockType.BLOCK_STONE);
		for (int j = 0; j < 1024; j++) blocks[4095][j].setBlockType(DataManager.BlockType.BLOCK_BEDROCK);
		
		
		// generate forests
		new ForestGenerator(blocks).pregenerate();
		
		// generate caves
		//new CaveGenerator(blocks).pregenerate();
		this.caveGenerate = new CaveGenerate(blocks);
	}
	
	private Block			blocks[][];
	private int				mapWidth;
	private int				mapHeight;
	
	private TreeGenerator	treeGenerator;
	private CaveGenerate	caveGenerate;

	private Random			randomizer = new Random();
	
	// Distance between two peaks(in blocks)
	private final int betweenDistances = 32;
}
